package io.bdmc.core.snmp;

import java.io.IOException;
import java.util.Vector;

import io.bdmc.core.snmp.cache.ConcurrentHashMapCacheUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.bdmc.common.utils.Constant;
import io.bdmc.modules.bss.service.IDeviceAlarmService;

/**
 * 本类用于监听代理进程的Trap信息
 * 
 * @author huanglu
 *
 */
@Component
public class MultiThreadedTrapReceiver implements CommandResponder {

	private static final Logger logger = LoggerFactory.getLogger(MultiThreadedTrapReceiver.class);

	@Autowired
	IDeviceAlarmService _alarmSvs;

	private Snmp snmp = null;

	private void init(String ip) throws IOException {
		ThreadPool threadPool = ThreadPool.create("Trap", 2);
		MultiThreadedMessageDispatcher dispatcher = new MultiThreadedMessageDispatcher(threadPool,
				new MessageDispatcherImpl());
		Address listenAddress = GenericAddress.parse(System.getProperty("snmp4j.listenAddress", "udp:" + ip + "/162")); // 本地IP与监听端口
		TransportMapping<?> transport;
		// 对TCP与UDP协议进行处理
		if (listenAddress instanceof UdpAddress) {
			transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
		} else {
			transport = new DefaultTcpTransportMapping((TcpAddress) listenAddress);
		}
		snmp = new Snmp(dispatcher, transport);
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
		USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
		SecurityModels.getInstance().addSecurityModel(usm);
		snmp.listen();
	}

	public void run(String ip) {
		try {
			init(ip);
			snmp.addCommandResponder(this);
			ConcurrentHashMapCacheUtils.setCache(Constant.Is162Startup, true);
			logger.info(Thread.currentThread().getName() + "start listen" + ip + "Trap");
		} catch (Exception ex) {
			ConcurrentHashMapCacheUtils.setCache(Constant.Is162Startup, false);
			ex.printStackTrace();
			logger.error(Thread.currentThread().getName() + "fail to listen:" + ip + ex.getMessage());
		}
	}

	/**
	 * 实现CommandResponder的processPdu方法, 用于处理传入的请求、PDU等信息 当接收到trap时，会自动进入这个方法
	 * 
	 * @param respEvent 响应事件
	 */
	public void processPdu(CommandResponderEvent respEvent) {
		// 解析Response
		if (respEvent != null && respEvent.getPDU() != null) {
			Vector<? extends VariableBinding> recVBs = respEvent.getPDU().getVariableBindings();
			String ipAdd = respEvent.getPeerAddress().toString().split("/")[0];

			for (int i = 0; i < recVBs.size(); i++) {
				VariableBinding recVB = recVBs.elementAt(i);
				if (recVB.getOid().toString().equals("1.3.6.1.4.1.48391.3.5.5.1")) {
					String result = ipAdd + "," + recVB.getVariable();
					logger.info(Thread.currentThread().getName() + "---" + result);
					SnmpDataCache.offTrapQueue(result);
				}
			}
		}
	}

}